#include "cilent.h"
#include <openssl/md5.h>
#define __BIG_FILE_SIZE__ (100*1024*1024)
//int recvn(int sockfd, void *buf, ssize_t length){
//    char *p = (char *)buf;//char* 是因为偏移以1个字节为单位
//    ssize_t cursize = 0;
//    while(cursize < length){
//        ssize_t sret = recv(sockfd,p+cursize,length-cursize,0);
//        cursize += sret;
//    }
//    return cursize;
//}
//
//
//int sendn(int sockfd,void *buf,ssize_t length){
//    char *p = (char *)buf;
//    ssize_t cursize = 0;
//    while(cursize < length){
//        ssize_t sret = send(sockfd,p+cursize,length-cursize,0);
//        cursize += sret;
//    }
//    return cursize;
//}
int getsCommand(int sockfd){
    int ret = 0;
    unsigned char recv_hash[256] = {0};
    
    // 接收哈希值 
    int hash_len = 0;
    ret = recvn(sockfd,&hash_len,sizeof(hash_len));
    printf("ret = %d\n",ret);
    ret = recvn(sockfd,recv_hash,hash_len);
    printf("ret = %d\n",ret);
    if(ret == -1){
        printf("哈希值接收失败！\n");
        return -1;
    }
    // md5准备
    MD5_CTX ctx;
    MD5_Init(&ctx);
    // 接收文件名
    char recvname[1024] = {0};
    int name_len = 0;
    ret = recvn(sockfd,&name_len,sizeof(name_len));
    if(ret == -1){
        printf("接收文件名长度失败！\n");
        return -1;
    }
    printf("namelen = %d\n",name_len);
    printf("ret = %d\n",ret);
    ret = recvn(sockfd,&recvname,name_len);
    if(ret == -1){
        printf("接收文件名失败！\n");
        return -1;
    }
    printf("ret = %d\n",ret);
    printf("recvname = %s\n",recvname);
    

    // 接收文件大小
    unsigned long filelen = 0;
    ret = recvn(sockfd,&filelen,sizeof(filelen));
    if(ret == -1){
        printf("接收文件大小失败!\n");
        return -1;
    }
    printf("文件大小：%ld\n",filelen);
    // 打开文件
    int filefd = open(recvname,O_RDWR|O_CREAT|O_EXCL,0666);
    int cursize = 0;
    if(filefd==-1){ // 文件已经存在
        filefd = open(recvname,O_RDWR);
        if(filefd == -1){
            printf("无法打开文件：%s\n",recvname);
            return -1;
        }
        struct stat state;
        fstat(filefd,&state);
        cursize = state.st_size;
        lseek(filefd,cursize,SEEK_SET);
    }


    // 发送当前文件大小
    ret = sendn(sockfd,&cursize,sizeof(cursize));
    if(ret == -1){
        printf("发送当前文件大小失败！\n");
        return -1;
    }
    printf("filelen = %ld\n",filelen);

    if(filelen > __BIG_FILE_SIZE__){
        char buf[1024];
        while(cursize < filelen){
            bzero(buf,sizeof(buf));
            unsigned long remain = filelen-cursize;
            int recv_len = remain < sizeof(buf)? remain:sizeof(buf);
            ret = recvn(sockfd,buf,recv_len);
            if(ret <= 0) break;
            
            // md5更新
            MD5_Update(&ctx,buf,ret);  // 将读到的文件更新到ctx中  
            write(filefd,buf,ret);
            cursize +=ret;
            printf("接受进度：%5.2f%%\r",100.00*cursize / filelen);
            fflush(stdout);
        }
    }else{
        char buf[1024];
        while(cursize < filelen){
            int data_len = 0;
            ret = recvn(sockfd,&data_len,sizeof(data_len));
            printf("ret = %d\n",ret);
            if(ret == -1) break;

            ret = recvn(sockfd,buf,data_len);
            printf("ret = %d\n",ret);
            if(ret == -1) break;
            write(filefd,buf,data_len);
            // md5更新
            MD5_Update(&ctx,buf,ret);
            cursize +=ret;
            printf("接受进度：%5.2f%%\r",100.00*cursize / data_len);
        }
    }

    printf("接收完成！文件总字节数：%d\n",cursize);
    close(filefd);

    // 计算最终的md5
    unsigned char local_md5[MD5_DIGEST_LENGTH];
    MD5_Final(local_md5,&ctx);
    char hash_str[33] = {0};
    for(int i = 0; i < 16; ++i){
        char temp[3] = {0};
        sprintf(temp,"%02x",local_md5[i]);
        strcat(hash_str,temp);
    }

    // 比较哈希值
    if(memcmp(recv_hash,hash_str,32)==0){
        printf("文件无误！\n");
    }else{
        printf("文件可能损坏！\n");
        return -1;
    }
    return 0;
}

